Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[API] Add Poem as an alternative backend #1906

Merged
merged 22 commits into from
Jul 22, 2022
Merged

[API] Add Poem as an alternative backend #1906

merged 22 commits into from
Jul 22, 2022

Conversation

banool
Copy link
Contributor

@banool banool commented Jul 12, 2022

Description

Read me: The new API is not ready to be deployed to prod as default, but I'm sharing it out now to get thoughts on the approach so far. Focus on the high level stuff. Each commit is mostly a neat unit, if you'd like to look at it that way. At this stage I'd like to land the PR as is and continue work in another PR (because this is getting too big). It should be fine to do this since it doesn't mess with the original API in any way.

Today we write our OpenAPI spec by hand, which is a constant source of errors stemming from the spec not matching the reality of the API. These manifest in the clients, which are generated from the spec file, resulting in errors from the user perspective. To fix this, we should instead generate our spec directly from our API. That is what this PR aims to do.

In this PR, I add an alternative web framework to the API crate using Poem. I try to be as uninvasive to the existing API as possible in this PR, so we can choose to cut over to / experiment with the alternative backend at our leisure.

Why Poem? Essentially it's the only legitimate framework in the Rust ecosystem today that supports generating an OpenAPI spec from a Rust API, particularly one as complex as ours. I looked at alternatives and found them lacking:

Nonetheless, Poem is a bit of a gamble, mostly because it's quite new. I'm using it for NHC already, but the stakes are lower there, plus NHC is less complex. Saying that, it works great there and I like the overall layout and feature completeness of Poem.

In its current form, the PR only adds the basic framework / boilerplate and a couple of endpoints, just to demonstrate what this kind of change would look like. As far as I can tell, this would ultimately result in much less boilerplate (no need for both the get_x and handle_x functions, no need to have a filter for context, etc.) in addition to the stated goal of being able to generate an OpenAPI spec.

Some other things missing from this are:

  • .with(metrics("get_x")): Poem has middleware that we could use for this. Poem also supports prometheus and opentelemetry directly.
  • CORS: Poem has middleware for this.
  • Logging: Middleware again.
  • Proper response objects, particularly for errors: This is easy, I just haven't done it yet.
  • failpoint: I just need to add this.
  • TLS stuff: Just need to add it, Poem supports this.

Test Plan

Run a node:

cargo run -p aptos -- node run-local-testnet

Hit it with queries. At this point, beyond the basics like / and the spec endpoints, I have implemented just the accounts endpoints. Here are some A/B tests for those, where the first request hits the warp path and the second hits the Poem path (v1):

curl localhost:8080
{"chain_id":40,"epoch":0,"ledger_version":"0","oldest_ledger_version":"0","ledger_timestamp":"0","node_role":"full_node"}

curl localhost:8080/v1
{"chain_id":40,"epoch":0,"ledger_version":0,"oldest_ledger_version":0,"ledger_timestamp":0,"node_role":"FullNode"}
curl http://localhost:8080/accounts/0x1 | jq .
{
  "sequence_number": "0",
  "authentication_key": "0x0000000000000000000000000000000000000000000000000000000000000001"
}

curl http://localhost:8080/v1/accounts/0x1 | jq .
{
  "sequence_number": 0,
  "authentication_key": "0x0000000000000000000000000000000000000000000000000000000000000001"
}
curl -H 'Accept: application/x-bcs' http://localhost:8080/accounts/0x1
// It just outputs JSON, the existing API only supports returning BCS for some endpoints, there is no Accept value that can make this work.

curl -H 'Accept: application/x-bcs' http://localhost:8080/v1/accounts/0x1
E0B0x0000000000000000000000000000000000000000000000000000000000000001
curl http://localhost:8080/accounts/0x1/resources | jq .[0]
{
  "type": "0x1::Coin::CoinInfo<0x1::TestCoin::TestCoin>",
  "data": {
    "decimals": "6",
    "name": "Test Coin",
    "supply": {
      "vec": []
    },
    "symbol": "TC"
  }
}

curl http://localhost:8080/v1/accounts/0x1/resources | jq .[0]
{
    "type": {
      "address": "0x1",
      "module": "Coin",
      "name": "CoinInfo",
      "generic_type_params": [
        "0x1::TestCoin::TestCoin"
      ]
    },
    "data": {
      "decimals": "6",
      "name": "Test Coin",
      "supply": {
        "vec": []
      },
      "symbol": "TC"
    }
}
curl http://localhost:8080/accounts/0x1/modules | jq .[1]
{
  "bytecode": "0xa11ceb0b0500000006010002030206050807070f0d081c200c3c04000000010001010001060900010a020362637308746f5f627974657300000000000000000000000000000000000000000000000000000000000000010001020000",
  "abi": {
    "address": "0x1",
    "name": "bcs",
    "friends": [],
    "exposed_functions": [
      {
        "name": "to_bytes",
        "visibility": "public",
        "is_entry": false,
        "generic_type_params": [
          {
            "constraints": []
          }
        ],
        "params": [
          "&T0"
        ],
        "return": [
          "vector<u8>"
        ]
      }
    ],
    "structs": []
  }
}

curl http://localhost:8080/v1/accounts/0x1/modules | jq .[1]
{
    "bytecode": "0xa11ceb0b0500000006010002030206050807070f0d081c200c3c04000000010001010001060900010a020362637308746f5f627974657300000000000000000000000000000000000000000000000000000000000000010001020000",
    "abi": {
      "address": "0x1",
      "name": "bcs",
      "friends": [],
      "exposed_functions": [
        {
          "name": "to_bytes",
          "visibility": "Public",
          "is_entry": false,
          "generic_type_params": [
            {
              "constraints": []
            }
          ],
          "params": [
            "&T0"
          ],
          "return": [
            "vector<u8>"
          ]
        }
      ],
      "structs": []
    }
}
curl http://localhost:8080/transactions?limit=1
{
  "type": "block_metadata_transaction",
  "version": "1210",
  "hash": "0xf6218d5fa26cd72ec6281d5af129f65637f844ecc9e2214af2b15a2e76bccf4f",
  "state_root_hash": "0x142c56c893b04d966361941529c7992fe3f4026f10ba033c2c316e90532e2ece",
  "event_root_hash": "0x062415baf3db2597e765ae8474d2c02bffef7e78e73c0ff3c9c2631f25c9afd5",
  "gas_used": "0",
  "success": true,
  "vm_status": "Executed successfully",
  "accumulator_root_hash": "0x259dc265dd6a1cc5cdd9c3e253c32827c4789dc20d2d8e6b133925f3a3267dd8",
  "changes": [
    {
      "type": "write_resource",
      "address": "0x1",
      "state_key_hash": "0xeac3bb50beedae400e2fcb24b4911cbaf61645d56eaa4a213e8354646ed7bbe2",
      "data": {
        "type": "0x1::block::BlockMetadata",
        "data": {
          "epoch_internal": "60000000",
          "height": "610",
          "new_block_events": {
            "counter": "610",
            "guid": {
              "id": {
                "addr": "0x1",
                "creation_num": "3"
              }
            }
          }
        }
      }
    },
    {
      "type": "write_resource",
      "address": "0x1",
      "state_key_hash": "0x8048c954221814b04533a9f0a9946c3a8d472ac62df5accb9f47c097e256e8b6",
      "data": {
        "type": "0x1::stake::ValidatorPerformance",
        "data": {
          "missed_votes": [
            "1"
          ],
          "num_blocks": "46"
        }
      }
    },
    {
      "type": "write_resource",
      "address": "0x1",
      "state_key_hash": "0x7b1615bf012d3c94223f3f76287ee2f7bdf31d364071128b256aeff0841b626d",
      "data": {
        "type": "0x1::timestamp::CurrentTimeMicroseconds",
        "data": {
          "microseconds": "1658348896790905"
        }
      }
    }
  ],
  "id": "0xbca3a0acc4dbaeb2f06faca7cd675d81748b8148b75f50eb705e125cf3a78d67",
  "epoch": "10",
  "round": "46",
  "events": [
    {
      "key": "0x03000000000000000000000000000000000000000000000000000000000000000000000000000001",
      "sequence_number": "609",
      "type": "0x1::block::NewBlockEvent",
      "data": {
        "epoch": "10",
        "failed_proposer_indices": [],
        "previous_block_votes": [
          true
        ],
        "proposer": "0x775c3335cf16783b338ef9d706e8ddafd33130c230271ebf2bf74082d7d17dbf",
        "round": "46",
        "time_microseconds": "1658348896790905"
      }
    }
  ],
  "previous_block_votes": [
    true
  ],
  "proposer": "0x775c3335cf16783b338ef9d706e8ddafd33130c230271ebf2bf74082d7d17dbf",
  "failed_proposer_indices": [],
  "timestamp": "1658348896790905"
}

# Different transaction, hard to time it.
curl http://localhost:8080/v1/transactions?limit=1
{
  "version": 1126,
  "hash": "0xe0ef1d8545db4cd5181c6aa740e24fa18e00b29a9b97a818b3a0e06d6cf13287",
  "state_root_hash": "0x25c6658e3b523a7e13d577bc9a74fb7d8a833aeb9869b87ad6350a75d936e318",
  "event_root_hash": "0x8e1c41fe6b6f1fa76d32cb8de6e9a9d86fb2d86def13b9d86ff7312cd4cf3cfe",
  "gas_used": 0,
  "success": true,
  "vm_status": "Executed successfully",
  "accumulator_root_hash": "0xa2b9f706f1d37c66f67f5a4d26d0e39850bdb3c5443d697952f603336eabbbda",
  "changes": [
    {
      "address": "0x1",
      "state_key_hash": "0xeac3bb50beedae400e2fcb24b4911cbaf61645d56eaa4a213e8354646ed7bbe2",
      "data": {
        "type": {
          "address": "0x1",
          "module": "block",
          "name": "BlockMetadata",
          "generic_type_params": []
        },
        "data": {
          "epoch_internal": "60000000",
          "height": "568",
          "new_block_events": {
            "counter": "568",
            "guid": {
              "id": {
                "addr": "0x1",
                "creation_num": "3"
              }
            }
          }
        }
      },
      "type": "WriteResource"
    },
    {
      "address": "0x1",
      "state_key_hash": "0x8048c954221814b04533a9f0a9946c3a8d472ac62df5accb9f47c097e256e8b6",
      "data": {
        "type": {
          "address": "0x1",
          "module": "stake",
          "name": "ValidatorPerformance",
          "generic_type_params": []
        },
        "data": {
          "missed_votes": [
            "1"
          ],
          "num_blocks": "4"
        }
      },
      "type": "WriteResource"
    },
    {
      "address": "0x1",
      "state_key_hash": "0x7b1615bf012d3c94223f3f76287ee2f7bdf31d364071128b256aeff0841b626d",
      "data": {
        "type": {
          "address": "0x1",
          "module": "timestamp",
          "name": "CurrentTimeMicroseconds",
          "generic_type_params": []
        },
        "data": {
          "microseconds": "1658348869903754"
        }
      },
      "type": "WriteResource"
    }
  ],
  "id": "0x3658ae71f8e45db398937edf0a174596db7729a778dd9d0a1e0b35167ad54f7e",
  "epoch": 10,
  "round": 4,
  "events": [
    {
      "key": "0x03000000000000000000000000000000000000000000000000000000000000000000000000000001",
      "sequence_number": 567,
      "type": "0x1::block::NewBlockEvent",
      "data": {
        "epoch": "10",
        "failed_proposer_indices": [],
        "previous_block_votes": [
          true
        ],
        "proposer": "0x775c3335cf16783b338ef9d706e8ddafd33130c230271ebf2bf74082d7d17dbf",
        "round": "4",
        "time_microseconds": "1658348869903754"
      }
    }
  ],
  "previous_block_votes": [
    true
  ],
  "proposer": "0x775c3335cf16783b338ef9d706e8ddafd33130c230271ebf2bf74082d7d17dbf",
  "failed_proposer_indices": [],
  "timestamp": 1658348869903754,
  "type": "BlockMetadataTransaction"
}

Notes:

  • The API is not meant to be compatible with the previous API. While this PR focuses on spec generation, the whole project focuses on API improvements across the board. Saying that, I keep the API the same where possible, but there are changes. You can see any changes in the different outputs above. We can discuss any changes we should make to those in this PR.
  • The enums use UpperPascalCase now, but I can change it back if anyone cares, I'm just trying to not override default behavior.
  • There's a lot of extra code right now since this PR doesn't alter the existing API at all.
  • The new code could be made less verbose with improvements to response types, errors, etc.

This change is Reviewable

@banool banool marked this pull request as draft July 12, 2022 04:56
@banool banool changed the title [API] Add boilerplate for using Poem as an alternative backend [API] Add Poem as an alternative backend Jul 12, 2022
@banool banool force-pushed the banool/generate_openapi branch 2 times, most recently from dab6d5b to bc8db5c Compare July 12, 2022 07:04
@banool
Copy link
Contributor Author

banool commented Jul 12, 2022

For the sake of completeness I experimented with utoipa: #1916.

@banool banool force-pushed the banool/generate_openapi branch from bc8db5c to 8f35ff9 Compare July 12, 2022 15:58
@banool banool requested review from JoshLind, davidiw and gregnazario and removed request for JoshLind and davidiw July 12, 2022 16:40
@sunli829
Copy link

If you end up choosing Poem, I can help you with any Poem-related issues you might have (I hope not) 😁

@banool
Copy link
Contributor Author

banool commented Jul 13, 2022

Awesome, glad to hear it! I'll continue to contribute back to Poem too.

@banool banool force-pushed the banool/generate_openapi branch 3 times, most recently from 01780fc to f1f6cd1 Compare July 19, 2022 04:34
Copy link
Contributor

@gregnazario gregnazario left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking generally good, a few comments

Comment on lines +15 to +35
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize, Deserialize)]
pub struct IdentifierWrapper(pub Identifier);

impl FromStr for IdentifierWrapper {
type Err = anyhow::Error;

fn from_str(s: &str) -> anyhow::Result<Self, anyhow::Error> {
Ok(IdentifierWrapper(Identifier::from_str(s)?))
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay so we need the wrappers for some derivable thing in poem? We'll likely need similar things anyways for AccountAddress as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we had access to Identifier we wouldn't, we could just derive the necessary type right there, but we don't, so currently we have to wrap it. This issue might provide a simpler solution though: poem-web/poem#323.

Comment on lines 6 to 7
#[macro_export]
macro_rules! impl_poem_type {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh fun fun, macros!

pub fn get_latest_ledger_info_poem(&self) -> Result<LedgerInfo, AptosErrorResponse> {
self.get_latest_ledger_info().map_err(|e| {
AptosErrorResponse::InternalServerError(Json(
AptosError::new(format_err!("Failed to retrieve ledger info: {}", e).to_string())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can probably just make these format! if you're converting them to a string anyways.

I do like this adding error codes though super slick.

If you're adding Json( to everything, I'd just make it a function AptosErrorResponse::internal_server_error(err: AptosError), or AptosErrorResponse::internal_server_error(msg: String, error_code: AptosErrorCode)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The response / error stuff definitely needs love, I'm just deferring it to later as less critical. Agreed it's too verbose right now.

match mime.as_ref() {
"application/json" => return Ok(AcceptType::Json),
"application/x-bcs" => return Ok(AcceptType::Bcs),
"*/*" => {}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, does it default to this? or would "application/*" be valid? Basically, if I curl the endpoint, do I need to specify the header?

Copy link
Contributor Author

@banool banool Jul 20, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You do not need to specify the header, it'll be json by default. You need to not error on */* since most clients add it by default.

Comment on lines +89 to +101
#[oai(
path = "/accounts/:address/modules",
method = "get",
operation_id = "get_account_modules",
tag = "ApiTags::General"
)]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this it's very clean

Comment on lines +61 to +62
// TODO: Figure out how to have certain fields be borrowed, like in the
// original implementation.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These should be able to all be borrowed if it's using the one from the Aptos logger. But it's not high priority.

pub struct AptosError {
message: String,
error_code: Option<AptosErrorCode>,
aptos_ledger_version: Option<U64>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't wait until we can get rid of the U64 :(

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you know what needs to be done to make this happen? I'd love to get rid of it too.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should just write something that converts types to a JSON type if it's u64, so when we deserialize it it comes back as a u64 instead of bothering with this middle type.

Comment on lines 28 to 43
let apis = (
AccountsApi {
context: context.clone(),
},
BasicApi {
context: context.clone(),
},
IndexApi { context },
);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's slick

Comment on lines 83 to 107
.nest("/", api_service)
// TODO: I prefer "spec" here but it's not backwards compatible.
// Consider doing it later if we cut over to this entirely.
// TODO: Consider making these part of the API itself.
.at("/openapi.json", spec_json)
.at("/openapi.yaml", spec_yaml)
.with(cors)
.around(middleware_log);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's change it to whatever we want it to be and not worry about the backwards compatibility. If there's a known way to commonly do it, we should use it.

@banool banool force-pushed the banool/generate_openapi branch 5 times, most recently from 6426760 to e86b21c Compare July 20, 2022 20:17
@banool banool marked this pull request as ready for review July 20, 2022 20:19
@banool banool force-pushed the banool/generate_openapi branch from e86b21c to 433d3c5 Compare July 20, 2022 20:21
@gregnazario gregnazario self-requested a review July 20, 2022 20:25
@banool banool force-pushed the banool/generate_openapi branch from 433d3c5 to 151bc2d Compare July 20, 2022 20:27
Copy link
Contributor

@gregnazario gregnazario left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks pretty straightforward, but let's do two things:

  1. Wait until after the branch cut
  2. Once we commit this, let's break it up into subtasks that you and I can split and work on together. There's a lot here and I know it's asking a bunch for one person to handle it alone.

Comment on lines +4 to +9
#[macro_export]
macro_rules! impl_poem_type {
($($ty:ty),*) => {
$(
impl ::poem_openapi::types::Type for $ty {
const IS_REQUIRED: bool = true;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you put a comment describing what this does above it?

Comment on lines 476 to +486
pub enum WriteSetChange {
DeleteModule {
address: Address,
state_key_hash: String,
module: MoveModuleId,
},
DeleteResource {
address: Address,
state_key_hash: String,
resource: MoveStructTag,
},
DeleteTableItem {
state_key_hash: String,
handle: HexEncodedBytes,
key: HexEncodedBytes,
},
WriteModule {
address: Address,
state_key_hash: String,
data: MoveModuleBytecode,
},
WriteResource {
address: Address,
state_key_hash: String,
data: MoveResource,
},
WriteTableItem {
state_key_hash: String,
handle: HexEncodedBytes,
key: HexEncodedBytes,
value: HexEncodedBytes,
},
DeleteModule(DeleteModule),
DeleteResource(DeleteResource),
DeleteTableItem(DeleteTableItem),
WriteModule(WriteModule),
WriteResource(WriteResource),
WriteTableItem(WriteTableItem),
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So all of these changes, change how they serialize right? So it's a breaking change to the REST API?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't change the structure of the serialization, but there are other breaking changes, e.g. around data format. For example, the new API tries to format numbers as numbers, not strings. Also some structs are unpacked, e.g. this kind of thing:

curl http://localhost:8080/accounts/0x1/resources | jq .[0]
{
  "type": "0x1::Coin::CoinInfo<0x1::TestCoin::TestCoin>",
  "data": {
    "decimals": "6",
    "name": "Test Coin",
    "supply": {
      "vec": []
    },
    "symbol": "TC"
  }
}

curl http://localhost:8080/v1/accounts/0x1/resources | jq .[0]
{
    "type": {
      "address": "0x1",
      "module": "Coin",
      "name": "CoinInfo",
      "generic_type_params": [
        "0x1::TestCoin::TestCoin"
      ]
    },
    "data": {
      "decimals": "6",
      "name": "Test Coin",
      "supply": {
        "vec": []
      },
      "symbol": "TC"
    }
}

Comment on lines +55 to +56
impl_poem_type!(EventKey);
impl_poem_parameter!(EventKey);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Someday it'll be nice to have these as derive macros

Comment on lines +33 to +35
// Poem will run on a different port.
let poem_address = attach_poem_to_runtime(&runtime, context.clone(), config)
.context("Failed to attach poem to runtime")?;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should make sure we open the port on 127.0.0.1 then

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I'll need to experiment with the various deployments to make sure this works. If we need to open a port, I'll have to make this a predefined port, not a randomly selected one.

pub struct AptosError {
message: String,
error_code: Option<AptosErrorCode>,
aptos_ledger_version: Option<U64>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should just write something that converts types to a JSON type if it's u64, so when we deserialize it it comes back as a u64 instead of bothering with this middle type.

@banool banool force-pushed the banool/generate_openapi branch from 7fa4e92 to ca5c73b Compare July 22, 2022 00:47
@banool banool added CICD:build-images when this label is present github actions will start build+push rust images from the PR. CICD:run-coverage run tests with test coverage instrumentation CICD:run-e2e-tests when this label is present github actions will run all land-blocking e2e tests from the PR labels Jul 22, 2022
@banool banool enabled auto-merge (squash) July 22, 2022 01:24
@github-actions
Copy link
Contributor

✅ Forge test success

Forge is land-blocking

all up : 5853 TPS, 2901 ms latency, 5300 ms p99 latency,no expired txns

@banool banool merged commit dc0ba4f into main Jul 22, 2022
@banool banool deleted the banool/generate_openapi branch July 22, 2022 01:52
hodlen pushed a commit to hodlen/aptos-core.fork that referenced this pull request Sep 9, 2022
* [API] Add crate to help types self-describe for the OpenAPI spec generator

* [API] Add boilerplate for using Poem as an alternative backend

* [API] Add support for index with Poem backend

* [API] Add TLS support to Poem backend

* [API] Add CORS for Poem API backend

* [API] Add support for logging middleware to the Poem backend

* [API] Add response status tracking to Poem backend

* [API] Break APIs up in Poem backend

* [API] Make a BCS payload type

* [API] Make all API types self-describe for generating an OpenAPI spec

* [API] Fix up Rosetta following adding IdentifierWrapper

* [API] Add request and response types for the JSON / BCS enum

* [API] Add headers to response in Poem backend

* [API] Add endpoint for get_account for Poem backend

* [API] Add /accounts/{address}/resources endpoint

* [API] Add /accounts/{address}/modules endpoint

* [API] Add /events/{event_key} endpoint

* [API] Add /accounts/{address}/events/{event_handle_struct}/{field_name} endpoint

* [API] Run both APIs alongside each other

* [API] Add GET /transactions

* fixup: Remove use_poem_backend_flag

* Add comments explaining what the aptos-openapi macros do
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CICD:build-images when this label is present github actions will start build+push rust images from the PR. CICD:run-coverage run tests with test coverage instrumentation CICD:run-e2e-tests when this label is present github actions will run all land-blocking e2e tests from the PR
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants